#include "./WizInnerMemoryAllocatorLokiChunk.hpp"


namespace Wiz
{
    namespace Inner
    {
        namespace Memory
        {
            namespace Allocator
            {
                namespace Loki
                {
                    namespace Chunk
                    {
                        Type::Type(::Wiz::Size8::In EleSz, ::Wiz::Count8::In EleCnt)
                            : m_ElementPtr(new ::Wiz::UInt8::Type[EleSz * EleCnt])
                            , m_ElementSize(EleSz)
                            , m_ElementTotal(EleCnt)
                            , m_FirstAvailable(0)
                            , m_CountAvailable(EleCnt)
                        {
                            ::Wiz::UInt8::Type i = 0;
                            ::Wiz::UInt8::Ptr TempPtr = this->m_ElementPtr;
                            for (; i < EleCnt; TempPtr += this->m_ElementSize)
                            {
                                *TempPtr = ++i;
                            }
                        }

                        Type::~Type()
                        {
                            delete[] this->m_ElementPtr;
                        }

                        ::Wiz::Void::Ptr Type::Allocate()
                        {
                            if (this->m_CountAvailable == 0)
                            {
                                return WIZ_NULLPTR;
                            }

                            ::Wiz::UInt8::Ptr ResultPtr =
                                this->m_ElementPtr + (this->m_FirstAvailable * this->m_ElementSize);
                            this->m_FirstAvailable = *ResultPtr;
                            this->m_CountAvailable--;
#if (WIZ_DEBUG_MODE == WIZ_CFG_TRUE)
                            m_AllocatedElement.Insert(ResultPtr);
#endif /// #if (WIZ_DEBUG_MODE == WIZ_CFG_TRUE)
                            return ResultPtr;
                        }

                        ::Wiz::Void::Type Type::Deallocate(::Wiz::Void::Ptr OldPtr)
                        {
                            ::Wiz::UInt8::Ptr ReleasePtr = ::Wiz::Cast::Static<::Wiz::UInt8::Ptr>(OldPtr);
#if (WIZ_DEBUG_MODE == WIZ_CFG_TRUE)
                            tDebugSet::tIterator Itr = m_AllocatedElement.Find(ReleasePtr);
                            if (Itr == m_AllocatedElement.End())
                            {
                                WIZ_ASSERT_COMMENT(::Wiz::Bool::False, "This memory does not allocated from here!");
                                return;
                            }
                            m_AllocatedElement.Erase(Itr);
#endif /// #if (WIZ_DEBUG_MODE == WIZ_CFG_TRUE)
                            WIZ_ASSERT(ReleasePtr >= this->m_ElementPtr);
                            WIZ_ASSERT(ReleasePtr < (this->m_ElementPtr + (this->m_ElementSize * this->m_ElementTotal)));
                            WIZ_ASSERT((ReleasePtr - this->m_ElementPtr) % this->m_ElementSize == 0);

                            *ReleasePtr = this->m_FirstAvailable;
                            this->m_FirstAvailable = (ReleasePtr - this->m_ElementPtr) / this->m_ElementSize;

                            this->m_CountAvailable++;
                        }
                    } /// end of namespace Chunk
                } /// end of namespace Loki
            } /// end of namespace Allocator
        } /// end of namespace Memory
    } /// end of namespace Inner
} /// end of namespace Wiz

